package org.szgb.console.sys.file.web;

import cn.hutool.http.HttpStatus;
import io.minio.GetObjectArgs;
import io.minio.GetObjectResponse;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.szgb.console.config.MinIOInfo;
import org.szgb.console.sys.file.entity.SysFile;
import org.szgb.console.sys.file.service.SysFileService;
import org.szgb.console.sys.user.entity.SysUser;
import org.szgb.console.utils.PageView;
import org.szgb.console.utils.TokenUtil;
import org.szgb.core.utils.AjaxJson;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

@Slf4j
@RestController
@RequestMapping(value = "/sys/file")
@Tag(name = "文件管理", description = "文件管理模块")
public class SysFileController {
    private final SysFileService sysFileService;
    private final MinioClient minioClient;
    private final MinIOInfo minIOInfo;

    @Autowired
    public SysFileController(SysFileService sysFileService, MinioClient minioClient, MinIOInfo minIOInfo) {
        this.sysFileService = sysFileService;
        this.minioClient = minioClient;
        this.minIOInfo = minIOInfo;
    }

    @Operation(summary = "获取文件信息", description = "根据查询参数获取文件信息，支持分页查询。使用id获取更详细的信息。")
    @PostMapping("/get")
    public AjaxJson get(@RequestBody(required = false) SysFile.SysFileFindDto findDto, HttpServletRequest request, HttpServletResponse response) {
        if(findDto == null){
            findDto = new SysFile.SysFileFindDto();
        }
        // 创建一个PageView对象，用于分页显示
        PageView<SysFile.SysFileView> pageView = new PageView<>();
        SysFile sysFile = findDto.toSysFile();
        // 如果实体对象的ID不为空，则直接调用get方法获取单个实体对象
        if (sysFile != null && sysFile.getId() != null && !sysFile.getId().isEmpty()) {
            SysFile file = sysFileService.get(sysFile.getId());
            // 如果实体对象为空，则返回错误响应
            if (file == null) {
                return AjaxJson.error("数据不存在", HttpStatus.HTTP_NOT_FOUND, request, response);
            }
            // 返回成功的响应，并将实体对象放入响应中
            return AjaxJson.success(request, response).put("sysFile", file.toSysFileView());
        } else {
            // 设置Page对象的列表属性，包含根据实体对象查询到的数据
            pageView.setList(SysFile.SysFileView.getViewListFromList(sysFileService.findList(sysFile)));
            // 设置Page对象的总记录数属性，用于分页显示
            pageView.setCount(sysFileService.getCount(sysFile));
            // 创建一个成功的AjaxJson对象，并放入Page对象，以便于前端展示
            return AjaxJson.success(request, response).put("page", pageView);
        }
    }

    @PostMapping(value = "/download")
    @Operation(summary = "下载文件", description = "下载文件。")
    public void download(@RequestBody SysFile.SysFileDownloadDto sysFileDownloadDto, HttpServletRequest request, HttpServletResponse response) throws Exception {
        SysFile sysFile = sysFileService.get(sysFileDownloadDto.toSysFile().getId());

        //后端设置一下响应头信息，方便浏览器弹出下载框
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(sysFile.getName()+sysFile.getSubFix(), StandardCharsets.UTF_8));
        // 从minion获取文件数据
        GetObjectResponse getObjectResponse = minioClient.getObject(GetObjectArgs.builder()
                .bucket(minIOInfo.getBucketName())
                .object(sysFile.getId()+sysFile.getSubFix())
                .build());

        getObjectResponse.transferTo(response.getOutputStream());
    }

    @PostMapping("/save")
    @Operation(summary = "修改文件名", description = "修改文件名。")
    public AjaxJson save(@RequestBody SysFile.SysFileSaveDto sysFileSaveDto, HttpServletRequest request, HttpServletResponse response) {
        if (sysFileSaveDto == null) {
            return AjaxJson.error("参数错误", HttpStatus.HTTP_BAD_REQUEST, request, response);
        }
        SysFile sysFile = sysFileSaveDto.toSysFile();
        // 设置实体对象的更新者为当前用户
        sysFile.setUpdatedBy(new SysUser(TokenUtil.getUid(request)));
        // 调用服务层的save方法，尝试保存或更新实体对象，返回保存结果的Map
        sysFileService.save(sysFile);
        // 根据保存结果返回相应的AjaxJson对象
        return AjaxJson.success("保存成功", request, response).put("sysFile", sysFile.toSysFileView());
    }

    @PostMapping("/upload")
    @Operation(summary = "上传文件", description = "上传文件。")
    public AjaxJson upload(MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception {
//        全文件名
        String filename = file.getOriginalFilename();
//        文件后缀
        String subFix = Objects.requireNonNull(filename).substring(filename.lastIndexOf("."));
        SysFile sysFile = new SysFile(filename.substring(0, filename.lastIndexOf(".")), subFix, file.getSize());
        sysFile.setUpdatedBy(new SysUser(TokenUtil.getUid(request)));
        sysFileService.save(sysFile);
//      上传图片到 MinIO
        minioClient.putObject(PutObjectArgs.builder().bucket(minIOInfo.getBucketName()) // 配置桶名称
                .object(sysFile.getId() + subFix) //设置对象名
                .stream(file.getInputStream(), file.getSize(), -1) //文件流
                .build());

        return AjaxJson.success(request, response).put("sysFile", sysFile.toSysFileView());
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除文件", description = "根据ID删除文件。", parameters = {@Parameter(name = "ids", description = "文件ID列表，多个ID用英文逗号分隔。")})
    public AjaxJson delete(@RequestParam String ids, HttpServletRequest request, HttpServletResponse response) {
        // 检查ID参数是否为空，为空则返回错误响应
        if (ids == null) {
            return AjaxJson.error("参数错误", HttpStatus.HTTP_BAD_REQUEST, request, response);
        }
        // 调用服务层方法，执行删除操作
        sysFileService.delete(ids);
        // 返回成功响应
        return AjaxJson.success(request, response);
    }
}
